package gormutil

import (
	"database/sql"
	"fmt"
	"os"
	"path/filepath"
	"reflect"
	"strconv"
	"strings"
	"sync"
	"time"
	"unicode"
	"unsafe"

	Log "github.com/cihub/seelog"
	"github.com/shopspring/decimal"

	"gorm.io/gorm"
	"gorm.io/gorm/clause"
	"gorm.io/gorm/logger"
)

var (
	gormInfoMap   = map[string]GormInfo{} //数据库对象集合
	gormWaitGroup sync.WaitGroup          //同步原语,要保证gorm被加载完毕
)

func init() {
	gormWaitGroup.Add(1) //等待第一个gorm被加载完毕
}

type GormInfo struct {
	Type   string   //数据库类型
	Name   string   //数据库对象名称
	GormDb *gorm.DB //数据库对象
}

// 数据源信息
type DataSourceInfo struct {
	Type        string `json:"type"`
	Name        string `json:"name"`
	User        string `json:"user"`
	Pass        string `json:"pass"`
	Ip          string `json:"ip"`
	Port        string `json:"port"`
	DbName      string `json:"dbName"`
	PrintSql    bool   `json:"printSql"`
	AutoMigrate bool   `json:"autoMigrate"` //是否开启AutoMigrate功能(会创建表、缺失的外键、约束、列和索引)
	PassKey     string `json:"passKey"`     //加密密钥
}

type TableInfo struct {
	DbName  string            `json:"dbName"`
	Name    string            `json:"name" gorm:"column:name; type:varchar"`
	Comment string            `json:"comment" gorm:"column:comment; type:varchar"`
	Fields  map[string]*Field `json:"fields"`
	Columns []*Field          `json:"columns"`
}

type Field struct {
	GsTableName    string `json:"sTableName" gorm:"column:sTableName; type:varchar; DEFAULT:''"`       //字段所在表名
	GsName         string `json:"sName" gorm:"column:sName; type:varchar; DEFAULT:''"`                 //在数据库中的名字段
	GsType         string `json:"sType" gorm:"column:sType; type:varchar; DEFAULT:''"`                 //字段类型
	GiNull         int    `json:"iNull" gorm:"column:iNull; type:int; DEFAULT:1"`                      //是否允许为空
	GiKey          int    `json:"iKey" gorm:"column:iKey; type:int; DEFAULT:2"`                        //是否主键
	GiAuto         int    `json:"iAuto" gorm:"column:iAuto; type:int; DEFAULT:2"`                      //是否自增长
	GiIndex        int    `json:"iIndex" gorm:"column:iIndex; type:int; DEFAULT:99"`                   //序号
	GsDefaultData  string `json:"sDefaultData" gorm:"column:sDefaultData; type:varchar; DEFAULT:''"`   //默认值
	GiMaxLength    int    `json:"iMaxLength" gorm:"column:iMaxLength; type:int; DEFAULT:-1"`           //字段长度
	GiDecimal      int    `json:"iDecimal" gorm:"column:iDecimal; type:int; DEFAULT:2"`                //类型是否有小数
	GiIntLen       int    `json:"iIntLen" gorm:"column:iIntLen; type:int; DEFAULT:0"`                  //整数位的长度
	GiDecimalLen   int    `json:"iDecimalLen" gorm:"column:iDecimalLen; type:int; DEFAULT:0"`          //小数位的长度
	GsComment      string `json:"sComment" gorm:"column:sComment; type:varchar; DEFAULT:''"`           //字段备注
	GsSimplComment string `json:"sSimplComment" gorm:"column:sSimplComment; type:varchar; DEFAULT:''"` //字段简洁备注(去除括号的内容)
	GiBigTxt       int    `json:"iBigTxt" gorm:"column:iBigTxt; type:varchar; DEFAULT:2"`              //是否大文本字段
}

// AddGorm 添加gorm实例
func AddGorm(gormInfo GormInfo) {
	gormWaitGroup.Done() //每添加一个gorm实例,减1
	gormInfoMap[gormInfo.Name] = gormInfo
}

// getDbType 获取数据库类型
func GetDbType(dbName string) string {
	if result, ok := gormInfoMap[dbName]; ok {
		return result.Type
	}

	gormWaitGroup.Wait() // 没找到则等待gorm被加载完毕

	if result, ok := gormInfoMap[dbName]; ok { //再次查找
		return result.Type
	}

	Log.Error("没有找到数据库连接:", dbName)

	return ""
}

// 获取数据库类型
func DbType(dbName string) string {
	db := GetGorm(dbName)
	return db.Dialector.Name()
}

// Gorm 获取默认(第一个)gorm实例
func DefaultGorm() *gorm.DB {
	if len(gormInfoMap) > 0 {
		for _, v := range gormInfoMap {
			return v.GormDb
		}
	}

	gormWaitGroup.Wait() // 没找到则等待gorm被加载完毕

	for _, v := range gormInfoMap { //再次查找
		return v.GormDb
	}

	return nil
}

// getGorm 获取gorm实例
func GetGorm(dbName string) *gorm.DB {
	if dbName == "" {
		return DefaultGorm()
	}

	if result, ok := gormInfoMap[dbName]; ok {
		return result.GormDb
	}

	gormWaitGroup.Wait() // 没找到则等待gorm被加载完毕

	if result, ok := gormInfoMap[dbName]; ok { //再次查找
		return result.GormDb
	}

	Log.Error("没有找到数据库连接:", dbName)

	return nil
}

/**
 * 创建数据库连接
 */
func NewDb(dataSourceInfo DataSourceInfo, dbOpenFun func(dsn string) gorm.Dialector) (bool, string, interface{}) {
	dbConfig := &gorm.Config{
		DisableForeignKeyConstraintWhenMigrating: !dataSourceInfo.AutoMigrate,
	}

	if dataSourceInfo.PrintSql {
		dbConfig.Logger = logger.Default.LogMode(logger.Info) //开启sql打印
	}

	var dsn string
	switch dataSourceInfo.Type {
	case "mysql":
		//dsn := "root:view@tcp(127.0.0.1:3306)/Dev_BricksBaseSystem?charset=utf8mb4&parseTime=True&loc=Local"
		//dsn := user + ":" + pass + "@tcp(" + ip + ":" + port + ")/" + dbName + "?charset=utf8mb4&serverTimezone=GMT%2B8&parseTime=True&loc=Local"
		dsn = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", dataSourceInfo.User, dataSourceInfo.Pass, dataSourceInfo.Ip, dataSourceInfo.Port, dataSourceInfo.DbName)

	case "sqlite":
		root := ""
		exePath, err := os.Executable()
		if err != nil {
			root = "."
		}

		root, _ = filepath.EvalSymlinks(filepath.Dir(exePath))

		dsn = dataSourceInfo.DbName
		if strings.HasPrefix(dsn, "./") {
			dsn = strings.Replace(dsn, "./", root+"/", 1)
			dsn = strings.Replace(dsn, "\\", "/", -1)
			dsn = strings.Replace(dsn, "//", "/", -1)
		}

		createFileDir(dsn)
	}

	db, err := gorm.Open(dbOpenFun(dsn), dbConfig)
	if err != nil {
		Log.Error("连接数据库错误:", err)
		return false, err.Error(), 1001
	}

	return true, "连接数据库成功", db
}

/**
 * 创建文件所在文件夹
 * 注意:必须是文件,否则只能创建出上级路径
 * @param filePath 文件路径
 * @return bool:是否成功(如果路径已经存在则不会创建,但返回true); error:错误信息
 */
func createFileDir(filePath string) (bool, error) {
	path := filepath.Dir(filePath) //获取上级目录
	_, err := os.Stat(path)        //os.Stat获取文件信息
	if err == nil {                //获取成功,说明文件存在
		return true, nil
	}

	if os.IsExist(err) { //再次判断路径是否存在,也可以使用os.IsNotExist(err)来判断是否不存在
		return true, nil
	}

	err = os.MkdirAll(path, os.ModePerm)
	if err != nil {
		return false, err
	}

	return true, nil
}

//------------- gorm操作方法 开始 ---------------//

func getDb(dbName string) (tx *gorm.DB) {
	if dbName == "" {
		return DefaultGorm()
	}

	return GetGorm(dbName)
}

func Create(dbName string, value interface{}) (tx *gorm.DB) {
	return getDb(dbName).Create(value)
}

func CreateInBatches(dbName string, value interface{}, batchSize int) (tx *gorm.DB) {
	return getDb(dbName).CreateInBatches(value, batchSize)
}

func Select(dbName string, query interface{}, args ...interface{}) (tx *gorm.DB) {
	return getDb(dbName).Select(query, args...)
}

// 获取第一条记录（主键升序）
func First(dbName string, dest interface{}, conds ...interface{}) (tx *gorm.DB) {
	return getDb(dbName).First(dest, conds...)
}

// 获取一条记录，没有指定排序字段
func Take(dbName string, dest interface{}, conds ...interface{}) (tx *gorm.DB) {
	return getDb(dbName).Take(dest, conds...)
}

// 获取最后一条记录（主键降序）
func Last(dbName string, dest interface{}, conds ...interface{}) (tx *gorm.DB) {
	return getDb(dbName).Last(dest, conds...)
}

// 当 QueryFields 被设置为 true 时，此行为默认进行
func Find(dbName string, dest interface{}, conds ...interface{}) (tx *gorm.DB) {
	return getDb(dbName).Find(dest, conds...)
}

// 当保存值不包含主键，它将执行 Create，否则它将执行 Update
func Save(dbName string, value interface{}) (tx *gorm.DB) {
	return getDb(dbName).Save(value)
}

// 当保存值不包含主键，它将执行 Create，否则它将执行 Update
func Delete(dbName string, value interface{}, conds ...interface{}) (tx *gorm.DB) {
	return getDb(dbName).Delete(value, conds...)
}

func Raw(dbName, sql string, values ...interface{}) (tx *gorm.DB) {
	return getDb(dbName).Raw(sql, values...)
}

func Exec(dbName, sql string, values ...interface{}) (tx *gorm.DB) {
	return getDb(dbName).Exec(sql, values...)
}

func Where(dbName string, query interface{}, args ...interface{}) (tx *gorm.DB) {
	return getDb(dbName).Where(query, args...)
}

func Table(dbName, name string, args ...interface{}) (tx *gorm.DB) {
	return getDb(dbName).Table(name, args...)
}

func Model(dbName string, value interface{}) (tx *gorm.DB) {
	return getDb(dbName).Model(value)
}

func Connection(dbName string, fc func(tx *gorm.DB) error) (err error) {
	return getDb(dbName).Connection(fc)
}

func Offset(dbName string, offset int) *gorm.DB {
	return getDb(dbName).Offset(offset)
}

func Clauses(dbName string, conds ...clause.Expression) *gorm.DB {
	return getDb(dbName).Clauses(conds...)
}

func Omit(dbName string, columns ...string) *gorm.DB {
	return getDb(dbName).Omit(columns...)
}

//------------- gorm操作方法 结束 ---------------//

//------------- gorm增强方法 开始 ---------------//

// 查询并返回指定类型结果
func FindData(dbName string, result interface{}, sql string, params ...interface{}) (bool, string, interface{}) {
	dbResult := getDb(dbName).Raw(sql, params...).Find(result)

	if dbResult.Error != nil {
		Log.Error("查询发生异常:", dbResult.Error)
		return false, "查询数据发生异常", 1002
	}

	if result == nil {
		return false, "没有数据", 1990 //没有数据
	}

	return true, "查询成功", result
}

// 查询单个字段
func FindColumn(dbName string, sql string, params ...interface{}) (bool, string, interface{}) {
	var data interface{}
	dbResult := getDb(dbName).Raw(sql, params...).Find(&data)

	if dbResult.Error != nil {
		Log.Error("查询发生异常:", dbResult.Error)
		return false, "查询数据发生异常", 1002
	}

	if data == nil {
		return false, "没有数据", 1990 //没有数据
	}

	return true, "查询成功", data
}

// 查询单条数据
func FindOne(dbName, sql string, params ...interface{}) (bool, string, interface{}) {
	var data map[string]interface{}
	dbResult := getDb(dbName).Raw(sql, params...).Find(&data)
	if dbResult.Error != nil {
		Log.Error("查询发生异常:", dbResult.Error)
		return false, "查询数据发生异常", 1002
	}

	if len(data) < 1 {
		return false, "没有数据", 1990 //没有数据
	}

	return true, "查询成功", data
}

// 查询列表
func FindList(dbName, sql string, params ...interface{}) (bool, string, interface{}) {
	var data []map[string]interface{}
	dbResult := getDb(dbName).Raw(sql, params...).Find(&data)
	if dbResult.Error != nil {
		Log.Error("查询发生异常:", dbResult.Error)
		return false, "查询数据发生异常", 1002
	}

	if len(data) < 1 {
		return false, "没有数据", 1990 //没有数据
	}

	return true, "查询成功", data
}

// ExecSql
func ExecSql(dbName, sql string, params ...interface{}) (bool, string, interface{}) {
	dbResult := getDb(dbName).Exec(sql, params...)
	if dbResult.Error != nil {
		Log.Error("执行更新发生异常:", dbResult.Error)
		return false, "更新数据发生异常:" + dbResult.Error.Error(), 7001
	}

	return true, "执行成功,影响数为", dbResult.RowsAffected
}

// 指定id数据是否存在,存在返回true
func HasById(dbName, tableName, idName string, idValue interface{}, delSignName string) (bool, string, interface{}) {
	txt := "SELECT COUNT(1) AS iCount FROM " + tableName + " WHERE " + idName + " = ?"
	if delSignName != "" {
		txt += " AND " + delSignName + " = 0"
	}

	var iCount int
	dbResult := getDb(dbName).Raw(txt, idValue).Find(&iCount)
	if dbResult.Error != nil {
		Log.Error("查询发生异常:", dbResult.Error)
		return false, "查询数据发生异常", 1002
	}

	if iCount == 0 {
		return false, "没有数据", 1990 //没有数据
	}

	return true, "数据存在", iCount
}

// 指定条件数据是否存在,存在返回true
func HasByWhere(dbName, tableName string, where map[string]interface{}) (bool, string, interface{}) {
	txt := "SELECT COUNT(1) AS iCount FROM " + tableName

	if len(where) > 0 {
		txt += " WHERE 1=1"
		for k, _ := range where {
			txt += " AND " + k + " = @" + k + " AND "
		}
	}

	txt = strings.Replace(txt, " WHERE 1=1 AND ", " WHERE ", -1)

	var iCount int
	var dbResult *gorm.DB
	if len(where) > 0 {
		dbResult = getDb(dbName).Raw(txt, where).Find(&iCount)
	} else {
		dbResult = getDb(dbName).Raw(txt).Find(&iCount)
	}

	if dbResult.Error != nil {
		Log.Error("查询发生异常:", dbResult.Error)
		return false, "查询数据发生异常", 1002
	}

	if iCount == 0 {
		return false, "没有数据", 1990 //没有数据
	}

	return true, "数据存在", iCount
}

// 查询指定id数据
func FindById(dbName, tableName, idName string, idValue interface{}, delSignName string) (bool, string, interface{}) {
	txt := "SELECT * FROM " + tableName + " WHERE " + idName + " = ?"
	if delSignName != "" {
		txt += " AND " + delSignName + " = 0"
	}

	var data map[string]interface{}
	dbResult := getDb(dbName).Raw(txt, idValue).Find(&data)
	if dbResult.Error != nil {
		Log.Error("查询发生异常:", dbResult.Error)
		return false, "查询数据发生异常", 1002
	}

	if len(data) < 1 {
		return false, "没有数据", 1990 //没有数据
	}

	return true, "查询成功", data
}

/**
 * 查询表名
 * @return bool
 */
func FindTable(dbName string, onlyTable bool) (bool, string, interface{}) {
	var text string
	if onlyTable {
		text = `
			SELECT table_comment AS 'comment', table_name AS 'name'
				FROM information_schema.tables
				WHERE table_schema = ? AND table_type = 'BASE TABLE'
				ORDER BY table_name`
	} else {
		text = `
			SELECT table_comment AS 'comment', table_name AS 'name'
				FROM information_schema.tables
				WHERE table_schema = ?
				ORDER BY table_name`
	}

	var data []*TableInfo
	tx := getDb(dbName).Raw(text, dbName).Scan(&data)
	if tx.Error != nil {
		Log.Error("查询发生异常:", tx.Error.Error())
		return false, "查询失败: " + tx.Error.Error(), 5002
	}

	result := make([]*TableInfo, 0)
	for _, v := range data {
		v.DbName = dbName
		result = append(result, v)
	}

	return true, "查询成功", result
}

// 查询表字段信息
func FindField(dbName, tableName string) (bool, string, interface{}) {
	text := findFieldSql(DbType(dbName))

	var data []*Field
	tx := getDb(dbName).Raw(text, dbName, tableName).Scan(&data)
	if tx.Error != nil {
		Log.Error("查询发生异常:", tx.Error.Error())
		return false, "查询失败: " + tx.Error.Error(), 5002
	}

	return true, "查询成功", data
}

// 查询表字段名信息
func FindFieldName(dbName, tableName string) (bool, string, interface{}) {
	text := findFieldNameSql(DbType(dbName))
	var data []string
	tx := getDb(dbName).Raw(text, dbName, tableName).Scan(&data)
	if tx.Error != nil {
		Log.Error("查询发生异常:", tx.Error.Error())
		return false, "查询失败: " + tx.Error.Error(), 5002
	}

	return true, "查询成功", data
}

// 统计数量
func FindCount(dbName, tableName string, where map[string]interface{}) (bool, string, interface{}) {
	whereStr := ""
	if len(where) > 0 {
		whereStr = " WHERE 1=1"
		for k, _ := range where {
			whereStr += " AND " + k + " = @" + k + " AND "
		}

		whereStr = strings.Replace(whereStr, " WHERE 1=1 AND ", " WHERE ", -1)
	}

	var count int64
	var err error
	if len(where) > 0 {
		err = getDb(dbName).Table(tableName).Where(whereStr, where).Count(&count).Error
	} else {
		err = getDb(dbName).Table(tableName).Count(&count).Error
	}

	if err != nil {
		return false, "查询失败: " + err.Error(), 5002
	}

	return true, "查询成功", count
}

// Create 创建记录
func Add(dbName, tableName string, data map[string]interface{}, keyName string, autoKey bool) (bool, string, interface{}) {
	tx := getDb(dbName).Table(tableName).Create(data)
	if tx.Error != nil {
		Log.Error("执行新增发生异常:", tx.Error.Error())
		return false, "新增失败: " + tx.Error.Error(), 1001
	}

	if v, ok := data["@id"]; ok { //自增组件会返回@id
		data[keyName] = v
		delete(data, "@id")
	}

	return true, "新增成功", data
}

// Edit 更新记录
func Edit(dbName, tableName string, data, where map[string]interface{}) (bool, string, interface{}) {
	whereStr := ""
	if len(where) > 0 {
		whereStr = " WHERE 1=1"
		for k, _ := range where {
			whereStr += " AND " + k + " = @" + k + " AND "
		}

		whereStr = strings.Replace(whereStr, " WHERE 1=1 AND ", " WHERE ", -1)
	}

	var tx *gorm.DB
	if len(where) > 0 {
		tx = getDb(dbName).Table(tableName).Where(whereStr, where).Updates(data)
	} else {
		tx = getDb(dbName).Table(tableName).Updates(data)
	}

	if tx.Error != nil {
		Log.Error("执行更新发生异常:", tx.Error.Error())
		return false, "更新失败: " + tx.Error.Error(), 5002
	}

	// 处理影响行数为0的情况
	if tx.RowsAffected > 0 {
		return true, "更新成功", tx.RowsAffected
	}

	return false, "更新失败,影响数为0", 5002
}

// Delete 删除记录
// 返回：QueryResult 包含操作结果
func Del(dbName, tableName string, where map[string]interface{}) (bool, string, interface{}) {
	whereStr := ""
	if len(where) > 0 {
		whereStr = " WHERE 1=1"
		for k, _ := range where {
			whereStr += " AND " + k + " = @" + k + " AND "
		}

		whereStr = strings.Replace(whereStr, " WHERE 1=1 AND ", " WHERE ", -1)
	}

	var tx *gorm.DB
	if len(where) > 0 {
		tx = getDb(dbName).Table(tableName).Where(whereStr, where).Delete(nil)
	} else {
		tx = getDb(dbName).Table(tableName).Delete(nil)
	}

	if tx.Error != nil {
		Log.Error("执行删除发生异常:", tx.Error.Error())
		return false, "删除失败: " + tx.Error.Error(), 5002
	}

	// 处理影响行数为0的情况
	if tx.RowsAffected > 0 {
		return true, "删除成功", tx.RowsAffected
	}

	return false, "删除失败,影响数为0", 5002
}

// MaxValue 查询最大值
func MaxValue(dbName, tableName, field string, where map[string]interface{}) (bool, string, interface{}) {
	whereStr := ""
	if len(where) > 0 {
		whereStr = " WHERE 1=1"
		for k, _ := range where {
			whereStr += " AND " + k + " = @" + k + " AND "
		}

		whereStr = strings.Replace(whereStr, " WHERE 1=1 AND ", " WHERE ", -1)
	}

	var tx *gorm.DB
	if len(where) > 0 {
		tx = getDb(dbName).Table(tableName).Where(whereStr, where)
	} else {
		tx = getDb(dbName).Table(tableName)
	}

	var max interface{}
	if err := tx.Select(fmt.Sprintf("MAX(%s) as max", field)).Scan(&max).Error; err != nil {
		return false, "查询失败: " + err.Error(), 5002
	}

	return true, "查询成功", max
}

// MinValue 查询最小值
func MinValue(dbName, tableName, field string, where map[string]interface{}) (bool, string, interface{}) {
	whereStr := ""
	if len(where) > 0 {
		whereStr = " WHERE 1=1"
		for k, _ := range where {
			whereStr += " AND " + k + " = @" + k + " AND "
		}

		whereStr = strings.Replace(whereStr, " WHERE 1=1 AND ", " WHERE ", -1)
	}

	var tx *gorm.DB
	if len(where) > 0 {
		tx = getDb(dbName).Table(tableName).Where(whereStr, where)
	} else {
		tx = getDb(dbName).Table(tableName)
	}

	var min interface{}
	if err := tx.Select(fmt.Sprintf("MIN(%s) as min", field)).Scan(&min).Error; err != nil {
		return false, "查询失败: " + err.Error(), 5002
	}

	return true, "查询成功", min
}

// 分组查询
func GroupValue(dbName, tableName string, where map[string]interface{}, groupFields []string, havings map[string]interface{}) (bool, string, interface{}) {
	whereStr := ""
	if len(where) > 0 {
		whereStr = " WHERE 1=1"
		for k, _ := range where {
			whereStr += " AND " + k + " = @" + k + " AND "
		}

		whereStr = strings.Replace(whereStr, " WHERE 1=1 AND ", " WHERE ", -1)
	}

	var tx *gorm.DB
	if len(where) > 0 {
		tx = getDb(dbName).Table(tableName).Where(whereStr, where)
	} else {
		tx = getDb(dbName).Table(tableName)
	}

	if len(groupFields) > 0 {
		temp := ""
		for _, field := range groupFields {
			if temp != "" {
				temp += ", "
			}
			temp = temp + field
		}

		tx = tx.Group(temp)
	}

	if len(havings) > 0 {
		temp := ""
		datas := []interface{}{}
		for field, data := range havings {
			if temp != "" {
				temp += " AND "
			}
			temp += field + " = @" + field
			datas = append(datas, data)
		}

		tx = tx.Having(temp, datas...)
	}

	rows, err := tx.Rows()
	if err != nil {
		Log.Error("查询发生异常:", tx.Error.Error())
		return false, "查询失败: " + err.Error(), 5003
	}

	defer rows.Close()

	res := scanRows2mapI(rows, false)
	if res == nil {
		Log.Error("查询成功后进行数据转换时发生异常,:无法正确转换")
		return false, "查询发生异常", 5003
	}

	if len(res) < 1 {
		return false, "没有数据", 1990 //没有数据
	}

	return true, "执行成功", removeNilFieldsFromSlice(res)
}

/**
 * 取指定节点下的子节点编号
 * @param dbName 数据库名
 * @param tableName 表名
 * @param idName 主键名
 * @param pidName 父节点字段名
 * @param pidValue 父节点值
 * @return
 */
func NewChildId(dbName, tableName, idName, pidName, pidValue string) (bool, string, interface{}) {
	txt := newChildIdSql(DbType(dbName), tableName, idName, pidName, pidValue)

	newId := ""
	dbResult := getDb(dbName).Raw(txt, sql.Named(pidName, pidValue)).Find(&newId)
	if dbResult.Error != nil {
		Log.Error("查询发生异常:", dbResult.Error)
		return false, "查询数据发生异常:" + dbResult.Error.Error(), 1001
	}

	return true, "获取子节点编号成功", newId
}

// 将查询结果转换成map数组,常用于原生sql查询
func scanRows2mapI(rows *sql.Rows, toCamel bool) []map[string]interface{} {
	defer rows.Close()

	columns, err := rows.Columns()
	if err != nil {
		return nil
	}

	values := make([]interface{}, len(columns))
	valuePtrs := make([]interface{}, len(columns))
	camelMap := make(map[string]string, len(columns))
	for i := range columns {
		valuePtrs[i] = &values[i]
		if toCamel {
			columns[i] = strToCamel(columns[i]) //转换驼峰
		} else {
			camelMap[columns[i]] = columns[i]
		}
	}

	colNames := make(map[string]string)
	temp, _ := rows.ColumnTypes() // 列信息
	for _, colType := range temp {
		colNames[colType.Name()] = strings.ToUpper(colType.DatabaseTypeName()) // 跟据数据库参数类型，创建默认值 和类型
	}

	maps := []map[string]interface{}{} //就算没数据也不会返回nil
	for rows.Next() {
		err := rows.Scan(valuePtrs...)
		if err != nil {
			return nil
		}

		m := make(map[string]interface{})
		for i, col := range columns {
			m[camelMap[col]] = dbValueCorrect(colNames[col], values[i])
		}

		maps = append(maps, m)
	}

	return maps
}

/**
 * 将查询结果修正成符合字段类型的数据
 * 比如DECIMAL类型的值如果不进行修正返回会是字符串
 * @param colType 数据库字段类型
 * @param val 数据库字段值
 * @return 修正后的数据
 */
func dbValueCorrect(colType string, val interface{}) interface{} {
	if val == nil {
		return nil
	}

	colType = strings.ToUpper(colType)
	switch colType {
	case "INT":
		value := toInt(val, -99999)
		if value != -99999 {
			return value
		}
	case "NUMERIC":
		value := toInt(val, -99999)
		if value != -99999 {
			return value
		}
	case "TINYINT":
		value := toInt(val, -99999)
		if value != -99999 {
			return value
		}
	case "BIGINT":
		value := toInt(val, -99999)
		if value != -99999 {
			return value
		}
	case "FLOAT":
		value := toFloat(val, 64, -99999999.99999999)
		if value != -99999999.99999999 {
			return value
		}
	case "DOUBLE":
		value := toFloat(val, 64, -99999999.99999999)
		if value != -99999999.99999999 {
			return value
		}
	case "DECIMAL":
		switch reflect.TypeOf(val).Elem().Name() {
		case "Decimal":
			return val.(*decimal.Decimal)
		case "uint8":
			temp, _ := decimal.NewFromString(toStr(val))
			return temp
		case "string":
			temp, _ := decimal.NewFromString(val.(string))
			return temp
		default:
			return val
		}
	case "DATETIME":
		return val.(time.Time).Format("2006-01-02 15:04:05")
	case "DATE":
		return val.(time.Time).Format("2006-01-02 15:04:05")
	case "TIME":
		return val.(time.Time).Format("2006-01-02 15:04:05")
	case "TIMESTAMP":
		return toInt(val, -99999)
	default:
		b, ok := val.([]byte)
		if ok {
			return string(b)
		}

		return val
	}

	return val //都不在范围内,不转换
}

// Byte转Str
func byte2Str(b []byte) string {
	return *(*string)(unsafe.Pointer(&b))
}

// 转换字符串
func toStr(data interface{}) string {
	switch obj := data.(type) {
	case []uint8:
		return byte2Str(obj)
	default:
		return fmt.Sprintf("%v", data)
	}
}

// 对象(字符串)转整型
func toInt(data interface{}, iDefault int) int {
	var str string
	switch obj := data.(type) {
	case []uint8:
		str = byte2Str(obj)
	default:
		str = fmt.Sprintf("%v", obj)
	}

	if str == "" { //字符串不能判断nil
		return iDefault
	}

	result, err := strconv.ParseInt(str, 10, 64)
	if err != nil {
		return iDefault
	}

	return int(result)
}

// 对象(字符串)转64整型
func toFloat(data interface{}, bitSize int, iDefault float64) float64 {
	var str string
	switch obj := data.(type) {
	case []uint8:
		str = byte2Str(obj)
	default:
		str = fmt.Sprintf("%v", obj)
	}

	if str == "" { //字符串不能判断nil
		return iDefault
	}

	result, err := strconv.ParseFloat(str, bitSize)
	if err != nil {
		return iDefault
	}

	return result
}

/**
 * 删除nil字段
 */
func removeNilFieldsFromSlice(s []map[string]interface{}) []map[string]interface{} {
	var result []map[string]interface{}
	for _, item := range s {
		result = append(result, removeNilFieldsFromMap(item))
	}

	return result
}

/**
 * 删除nil字段
 */
func removeNilFieldsFromMap(m map[string]interface{}) map[string]interface{} {
	result := make(map[string]interface{})
	for k, v := range m {
		if v != nil {
			result[k] = v
		}
	}

	return result
}

// 查询表字段信息
func findFieldSql(dbType string) string {
	return `
SELECT 
	sTableName,
	sName,
	sType,
	iNull,
	iKey,
	iAuto,
	iIndex,
	sDefaultData,
	CASE iMaxLength
	WHEN sType THEN -1
	ELSE iMaxLength
	END AS 'iMaxLength',
	iDecimal,
	iIntLen,
	iDecimalLen,
	sComment,
	sSimplComment,
	iBigTxt
FROM (
	SELECT
		table_name AS 'sTableName',
		COLUMN_NAME AS 'sName',
		DATA_TYPE AS 'sType',
		CASE DATA_TYPE
			WHEN 'datetime' THEN 30
			WHEN 'date' THEN 30
			WHEN 'time' THEN 30
			WHEN 'decimal' THEN SUBSTRING_INDEX(SUBSTRING(COLUMN_TYPE, LOCATE('(', COLUMN_TYPE) + 1), ',', 1)
			ELSE SUBSTRING_INDEX(SUBSTRING(COLUMN_TYPE, LOCATE('(', COLUMN_TYPE) + 1), ')', 1)
		END AS iMaxLength,
		CASE DATA_TYPE
			WHEN 'decimal' THEN 1
			ELSE 0
		END AS 'iDecimal',
		CASE DATA_TYPE
			WHEN 'decimal' THEN CONVERT(SUBSTRING_INDEX(SUBSTRING(COLUMN_TYPE, LOCATE('(', COLUMN_TYPE) + 1), ',', 1), UNSIGNED INTEGER) - 1 - CONVERT(SUBSTRING_INDEX(SUBSTRING(COLUMN_TYPE, LOCATE(',', COLUMN_TYPE) + 1), ')', 1), UNSIGNED INTEGER)
			ELSE 0
		END AS 'iIntLen',
		CASE DATA_TYPE
			WHEN 'decimal' THEN CONVERT(SUBSTRING_INDEX(SUBSTRING(COLUMN_TYPE, LOCATE(',', COLUMN_TYPE) + 1), ')', 1), UNSIGNED INTEGER)
			ELSE 0
		END AS iDecimalLen,
		CASE IS_NULLABLE
		WHEN 'NO' THEN 0
		ELSE 1
		END AS 'iNull',
		CASE column_key
		WHEN 'PRI' THEN 1
		ELSE 0
		END AS 'iKey',
		CASE EXTRA
		WHEN 'auto_increment' THEN 1
		ELSE 0
		END AS 'iAuto',
		ordinal_position AS 'iIndex',
		IFNULL(column_default, '<nil>') AS 'sDefaultData',
		COLUMN_Comment AS 'sComment',
		SUBSTRING_INDEX(COLUMN_Comment, '(', 1) AS 'sSimplComment',
		CASE DATA_TYPE
			WHEN 'text' THEN 1
			WHEN 'longtext' THEN 1
			WHEN 'tinytext' THEN 1
			WHEN 'tinyblob' THEN 1
			WHEN 'longblob' THEN 1
			WHEN 'blob' THEN 1
			ELSE 0
		END AS 'iBigTxt'
	FROM information_schema.columns
	WHERE table_schema = ?
	AND table_name = ?
	ORDER BY ordinal_position
) AS temp`
}

// 查询表字段名信息
func findFieldNameSql(dbType string) string {
	if dbType == "mysql" {
		return `
SELECT
	COLUMN_NAME AS 'sName'
FROM information_schema.columns
WHERE table_schema = ?
AND table_name = ?
ORDER BY ordinal_position`
	}

	if dbType == "dm" {
		return ""
	}

	return `
SELECT
	COLUMN_NAME AS 'sName'
FROM information_schema.columns
WHERE table_schema = ?
AND table_name = ?
ORDER BY ordinal_position`
}

/**
 * 取指定节点下的子节点编号
 * @param dbName 数据库名
 * @param tableName 表名
 * @param idName 主键名
 * @param pidName 父节点字段名
 * @param pidValue 父节点值
 * @return
 */
func newChildIdSql(dbType, tableName, idName, pidName, pidValue string) string {
	var build strings.Builder
	build.WriteString("SELECT CONCAT(pid, LPAD(RIGHT((cur + 1), 2), 2, '0') ) AS newId FROM (")
	build.WriteString(" 		select 0 as cur, 99999998 as nxt, @pid AS pid ")
	build.WriteString(" 		union")
	build.WriteString(" 		select cast(A.${MajorKeyString} AS SIGNED) AS cur, IFNULL(")
	build.WriteString(" 			(select MIN( CAST(B.${MajorKeyString} as signed integer)) from ${DbTableName} AS B")
	build.WriteString(" 				where cast(B.${MajorKeyString} AS SIGNED) > cast(A.${MajorKeyString} AS SIGNED)")
	build.WriteString(" 				and B.${PidKey} = @pid")
	build.WriteString(" 				and CAST(B.${MajorKeyString} as signed integer) != 0")                                             // 过滤字段中含非数字的记录
	build.WriteString(" 				and CAST(B.${MajorKeyString} as signed integer) = CAST(B.${MajorKeyString} as signed integer) +0") // 过滤字段中含非数字的记录
	build.WriteString(" 			), 99999999) AS nxt, @pid AS pid")
	build.WriteString(" 		from ${DbTableName} AS A")
	build.WriteString(" 		where A.${PidKey} = @pid")
	build.WriteString(" 		and CAST(A.${MajorKeyString} as signed integer) != 0")                                             // 过滤字段中含非数字的记录
	build.WriteString(" 		and CAST(A.${MajorKeyString} as signed integer) = CAST(A.${MajorKeyString} as signed integer) +0") // 过滤字段中含非数字的记录
	build.WriteString(" 	) AS D")
	build.WriteString(" WHERE (nxt - cur > 1) or (nxt = 99999999)")
	build.WriteString(" ORDER BY nxt DESC, cur")
	build.WriteString(" LIMIT 0, 1")

	txt := build.String()
	txt = strings.Replace(txt, "${DbTableName}", tableName, -1)
	txt = strings.Replace(txt, "${PidKey}", pidName, -1)
	txt = strings.Replace(txt, "${MajorKeyString}", idName, -1)
	txt = strings.Replace(txt, "@pid", "@"+pidName, -1)

	return txt
}

// 将字符串转换为小驼峰格式，并保留中文
func strToCamel(s string) string {
	if s == "" {
		return ""
	}

	var result strings.Builder
	var words []string

	// 按照下划线或空格分割
	currentWord := strings.Builder{}
	for _, r := range s {
		if r == '_' || unicode.IsSpace(r) {
			if currentWord.Len() > 0 {
				words = append(words, currentWord.String())
				currentWord.Reset()
			}
			continue
		}
		if isChinese(r) {
			if currentWord.Len() > 0 {
				words = append(words, currentWord.String())
				currentWord.Reset()
			}
			words = append(words, string(r))
		} else {
			currentWord.WriteRune(r)
		}
	}
	if currentWord.Len() > 0 {
		words = append(words, currentWord.String())
	}

	if len(words) == 0 {
		return ""
	}

	// 处理第一个单词：如果是中文就直接拼接，否则首字母小写
	first := words[0]
	if !isChinese([]rune(first)[0]) {
		result.WriteString(strings.ToLower(first))
	} else {
		result.WriteString(first)
	}

	// 后续单词：中文直接拼接，英文首字母大写
	for i := 1; i < len(words); i++ {
		word := words[i]
		runes := []rune(word)
		if len(runes) == 0 {
			continue
		}
		if isChinese(runes[0]) {
			result.WriteString(word)
		} else {
			result.WriteString(strings.ToUpper(string(runes[0])) + string(runes[1:]))
		}
	}

	return result.String()
}

// Byte转Str
func Byte2Str(b []byte) string {
	return *(*string)(unsafe.Pointer(&b))
}

// 是否小写开头
func isLowerStart(s string) bool {
	if len(s) == 0 {
		return false // 空字符串不被视为以小写字母开头
	}

	runeValue := rune(s[0])
	return unicode.IsLower(runeValue)
}

// 是否大写开头
func isUpperStart(s string) bool {
	if len(s) == 0 {
		return false // 空字符串不被视为以大写字母开头
	}

	runeValue := rune(s[0])
	return unicode.IsUpper(runeValue)
}

// IsChinese 判断一个字符是否是中文
func isChinese(char rune) bool {
	return unicode.Is(unicode.Scripts["Han"], char)
}

//------------- gorm增强方法 结束 ---------------//
